package com.et.machine.goods

import android.os.Environment
import android.util.Log
import android.webkit.MimeTypeMap
import com.et.api.MachineConfig
import com.et.drive.info.LightStatusEnum
import com.et.drive.info.LightTemperatureInfo
import com.et.drive.info.TemperatureStateEnum
import com.et.drive.info.Time
import com.et.logger.ELog
import com.et.logger.TAGS
import com.et.machine.BuildConfig
import com.et.machine.convert.lightTemperatureInfo
import com.et.machine.convert.machineInfo
import com.et.machine.manager.api.OutGoodsManager
import com.et.machine.manager.api.OutGoodsParamAndroid
import com.et.machine.store.ChannelEntity
import com.et.machine.store.DISABLED
import com.et.machine.store.ENABLED
import com.et.util.download
import com.et.util.insertByte
import com.et.util.violationsTrim
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import java.io.File


data class PushGoodsGson(
    @SerializedName("data") val channels: MutableList<Channel>,
    @SerializedName("goods") val goods: MutableList<Goods>
) {

    data class Channel(
        @SerializedName("goodsID") val goodsId: String,
        @SerializedName("guihao") val box: String,
        @SerializedName("road") val channel: String,
        @SerializedName("price") val priceDime: String,
        @SerializedName("barcode") val barcode: String,
    ) {
        override fun toString(): String {
            return "Channel(goodsId='$goodsId', box='$box', channel='$channel', priceDime='$priceDime', barcode='$barcode')"
        }
    }

    data class Goods(
        @SerializedName("barcode") val barcode: String,
        @SerializedName("picUrl") val imageUrl: String,
        @SerializedName("name") var goodsName: String,
    ) {
        override fun toString(): String {
            return "Goods(barcode='$barcode', imageUrl='$imageUrl', goodsName='$goodsName')"
        }
    }

    override fun toString(): String {
        return "PushGoodsGson(channels=$channels, goods=$goods)"
    }
}

data class AddGoodsGson(
    @SerializedName("data") val data: MutableList<Data>,
    @SerializedName("avm") val avm: String,
    @SerializedName("time") val time: String,
    @SerializedName("type") val type: String,
) {
    data class Data(
        @SerializedName("container") val container: String,
        @SerializedName("rtime") val rtime: String,
        @SerializedName("issend") val issend: String,
        @SerializedName("road") val channel: String,
        @SerializedName("jiahuo") val jiahuo: String,
        @SerializedName("avm") val avm: String,
        @SerializedName("ctime") val ctime: String,
        @SerializedName("guihao") val box: String,
        @SerializedName("username") val username: String,
    ) {
        override fun toString(): String {
            return "Data(container='$container', rtime='$rtime', issend='$issend', road='$channel', jiahuo='$jiahuo', avm='$avm', ctime='$ctime', ctiguihaome='$box', username='$username')"
        }
    }

    override fun toString(): String {
        return "AddGoodsGson(data=$data, avm='$avm', time='$time', type='$type')"
    }
}

data class MachineConfigGson(
    @SerializedName("data") val data: Data,
    @SerializedName("avm") val avm: String,
    @SerializedName("time") val time: String,
    @SerializedName("type") val type: String,
) {
    data class Data(
        @SerializedName("rv") val rv: String,
        @SerializedName("coolTP") val coolTP: String,
        @SerializedName("issend") val issend: String,
        @SerializedName("lv") val lv: String,
        @SerializedName("light_switch") val light_switch: String,
        @SerializedName("light") val light: String,
        @SerializedName("avm") val avm: String,
        @SerializedName("heatTP") val heatTP: String,
        @SerializedName("lightTime") val lightTime: String,
        @SerializedName("guihao") val box: String,
        @SerializedName("energy") val energy: String,
        @SerializedName("username") val username: String
    ) {
        override fun toString(): String {
            return "Data(rv='$rv', coolTP='$coolTP', issend='$issend', lv='$lv', light_switch='$light_switch', light='$light', avm='$avm', heatTP='$heatTP', lightTime='$lightTime', guihao='$box', energy='$energy', username='$username')"
        }
    }

    override fun toString(): String {
        return "MachineConfig(data=$data, avm='$avm', time='$time', type='$type')"
    }

}

data class OutGoodsJson(
    @SerializedName("gmt_payment") val date: String,
    @SerializedName("qrcode_id") val qrcode_id: String,
    @SerializedName("avm") val avm: String,
    @SerializedName("type") val type: String,
    @SerializedName("rows") val rows: MutableList<Rows>,
    @SerializedName("board") val board: String
) {
    data class Rows(
        @SerializedName("out_trade_no") val out_trade_no: String,
        @SerializedName("flag") val flag: String,
        @SerializedName("actualmoney") val actualmoney: Int,
        @SerializedName("aisleNo") val aisleNo: String,
        @SerializedName("price") val price: Int,
        @SerializedName("name") val name: String,
        @SerializedName("pay") val pay: String,
        @SerializedName("box") val box: String,
        @SerializedName("aisle") val aisle: String,
        @SerializedName("barcode") val barcode: String
    ) {
        override fun toString(): String {
            return "Rows(out_trade_no='$out_trade_no', flag='$flag', actualmoney=$actualmoney, aisleNo='$aisleNo', price=$price, name=$name, pay='$pay', box='$box', aisle='$aisle', barcode='$barcode')"
        }
    }

    override fun toString(): String {
        return "OutGoodsJson(gmt_payment=$date, qrcode_id='$qrcode_id', avm='$avm', type='$type', rows=$rows, board='$board')"
    }
}

data class DiscountGson(
    @SerializedName("avm") val avm: String,
    @SerializedName("discount") val newDiscount: String,
    @SerializedName("time") val time: String,
    @SerializedName("type") val type: String,
    @SerializedName("barcode") val barcode: String,
) {
    override fun toString(): String {
        return "DiscountGson(avm='$avm', discount='$newDiscount', time='$time', type='$type', barcode='$barcode')"
    }
}

fun goodsUpdate(s: String) {
    Single.just(s).map { json ->
        Gson().fromJson(json, PushGoodsGson::class.java).apply {
            Log.d(TAGS.machine, this.toString())
            val map = HashMap<String, PushGoodsGson.Goods>()
            if (goods.isNotEmpty()) {
                goods.forEach {
                    map[it.barcode] = it.apply {
                        goodsName = goodsName.violationsTrim()
                    }
                }
            }
            val list = mutableListOf<ChannelEntity>()
            if (channels.isNotEmpty()) {
                channels.forEach { channel ->
                    MachineConfig.setChannelInfo(
                        channel.box.toInt(),
                        channel.channel.toInt(),
                        channel.goodsId.toInt(16),
                        channel.priceDime.toInt() * 10,
                        false
                    )
                    list.add(
                        ChannelEntity.create(
                            box = channel.box.toInt(),
                            channel = channel.channel.toInt(),
                            priceCent = channel.priceDime.toInt() * 10,
                            barcode = channel.barcode,
                            status = if (channel.goodsId == "ee") DISABLED else ENABLED,
                            discount = globalDiscountMap[channel.barcode] ?: 100
                        ).apply {
                            map[channel.barcode]?.let { it ->
                                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
                                    .also { picture ->
                                        if (!picture.exists()) picture.mkdir()
                                        if (picture.exists() && picture.isDirectory) {
                                            val ext =
                                                MimeTypeMap.getFileExtensionFromUrl(it.imageUrl)
                                            File(picture, "${it.goodsName}.$ext").apply {
                                                image = absolutePath
                                                download(it.imageUrl) { f ->
                                                    if (f < 0f) {
                                                        ELog.d(
                                                            TAGS.vending,
                                                            "vending:download image failed>>${it.imageUrl}"
                                                        )
                                                    } else if (f == 1f) {
                                                        ELog.d(
                                                            TAGS.vending,
                                                            "vending:download image finish>>${it.imageUrl}"
                                                        )
                                                    }
                                                }
                                            }
                                        }
                                    }
                                name = it.goodsName
                            }
                        }
                    )
                }
            }
            GoodsHelper.getInstance().adds(list) // update database
        }
    }
        .subscribeOn(Schedulers.single())
        .observeOn(Schedulers.single())
        .subscribe({
            Log.d(TAGS.machine, it.toString())
        }, {
            if (BuildConfig.DEBUG) Log.e(TAGS.machine, "machine:update goods>>", it)
        })
}

fun goodsCountUpdate(s: String) {
    Single.just(s).map { json ->
        Gson().fromJson(json, AddGoodsGson::class.java).apply {
            Log.d(TAGS.machine, this.toString())
            if (data.isNotEmpty()) {
                data.forEach {
                    if (it.jiahuo.isNotEmpty()) {
                        globalChannelEntityMap[it.box.toInt() * 1000 + it.channel.toInt()]?.let { channelEntity ->
                            GoodsHelper.getInstance().add(
                                channelEntity.apply {
                                    quantity = it.jiahuo.toInt()
                                }
                            )
                        }
                        MachineConfig.setGoodsNumber(
                            it.box.toInt(),
                            it.channel.toInt(),
                            it.jiahuo.toInt(),
                        )
                    }

                }
            }
        }
    }
        .subscribeOn(Schedulers.single())
        .observeOn(Schedulers.single())
        .subscribe({
            Log.d(TAGS.machine, it.toString())
        }, {
            if (BuildConfig.DEBUG) Log.e(TAGS.machine, "machine:add goods>>", it)
        })
}

fun tempLightUpdate(s: String) {
    Single.just(s).map { json ->
        Gson().fromJson(json, MachineConfigGson::class.java).apply {
            Log.d(TAGS.machine, this.toString())
            data.let {
                MachineConfig.setSystemState(
                    lightSenior = it.light_switch == "1",
                    notDetectGoods = false,
                    lightTemperatureInfo = lightTemperatureInfo[it.box.toInt()]?.apply {
                        settingCoolTemperature = it.coolTP.substring(1).toInt()
                        settingHotTemperature = it.heatTP.substring(1).toInt()
                        rightRoomStatus = when (it.rv) {
                            "00" -> TemperatureStateEnum.Cool
                            "01" -> TemperatureStateEnum.Hot
                            "02" -> TemperatureStateEnum.Disable
                            else -> TemperatureStateEnum.Disable
                        }
                        leftRoomStatus = when (it.lv) {
                            "00" -> TemperatureStateEnum.Cool
                            "01" -> TemperatureStateEnum.Hot
                            "02" -> TemperatureStateEnum.Disable
                            else -> TemperatureStateEnum.Disable
                        }
                        lightStatus = when (it.light) {
                            "00" -> LightStatusEnum.Auto
                            "01" -> LightStatusEnum.AlwaysClose
                            "02" -> LightStatusEnum.AlwaysOpen
                            else -> LightStatusEnum.AlwaysClose
                        }
                        openLightTime = Time(
                            it.lightTime.substring(0, 2).toInt(),
                            it.lightTime.substring(2, 4).toInt(),
                            it.lightTime.substring(4, 6).toInt(),
                            it.lightTime.substring(6, 8).toInt()
                        )
                        energySavingTime = Time(
                            it.energy.substring(0, 2).toInt(),
                            it.energy.substring(2, 4).toInt(),
                            it.energy.substring(4, 6).toInt(),
                            it.energy.substring(6, 8).toInt()
                        )

                    } ?: LightTemperatureInfo(
                        settingCoolTemperature = it.coolTP.substring(1).toInt(),
                        settingHotTemperature = it.heatTP.substring(1).toInt(),
                        rightRoomStatus = when (it.rv) {
                            "00" -> TemperatureStateEnum.Cool
                            "01" -> TemperatureStateEnum.Hot
                            "02" -> TemperatureStateEnum.Disable
                            else -> TemperatureStateEnum.Disable
                        },
                        leftRoomStatus = when (it.lv) {
                            "00" -> TemperatureStateEnum.Cool
                            "01" -> TemperatureStateEnum.Hot
                            "02" -> TemperatureStateEnum.Disable
                            else -> TemperatureStateEnum.Disable
                        },
                        lightStatus = when (it.light) {
                            "00" -> LightStatusEnum.Auto
                            "01" -> LightStatusEnum.AlwaysClose
                            "02" -> LightStatusEnum.AlwaysOpen
                            else -> LightStatusEnum.AlwaysClose
                        },
                        openLightTime = Time(
                            it.lightTime.substring(0, 2).toInt(),
                            it.lightTime.substring(2, 4).toInt(),
                            it.lightTime.substring(4, 6).toInt(),
                            it.lightTime.substring(6, 8).toInt()
                        ),
                        energySavingTime = Time(
                            it.energy.substring(0, 2).toInt(),
                            it.energy.substring(2, 4).toInt(),
                            it.energy.substring(4, 6).toInt(),
                            it.energy.substring(6, 8).toInt()
                        ),
                        deviceNumber = it.box.toInt(),
                        actualCoolTemperature = 0,
                        actualHotTemperature = 0,
                        salesConfig = false.insertByte((it.light_switch == "1").insertByte(0, 3), 5)
                            .toInt()
                    )
                )
            }
        }
    }
        .subscribeOn(Schedulers.single())
        .observeOn(Schedulers.single())
        .subscribe({
            Log.d(TAGS.machine, it.toString())
        }, {
            if (BuildConfig.DEBUG) Log.e(TAGS.machine, "machine:machine temp light>>", it)
        })
}

fun outGoods(s: String) {
    Single.just(s).map { json ->
        Gson().fromJson(json, OutGoodsJson::class.java).apply {
            Log.d(TAGS.machine, this.toString())
            if (avm == machineInfo?.uuid) {
                rows.forEach {
                    OutGoodsManager.getInstance().commitOutGoodsTask(
                        OutGoodsParamAndroid(
                            it.pay.toInt(),
                            it.box.toInt(),
                            it.aisle.toInt(),
                            it.price / 10
                        )
                    )
                }
            }
        }
    }
        .subscribeOn(Schedulers.single())
        .observeOn(Schedulers.single())
        .subscribe({
            Log.d(TAGS.machine, it.toString())
        }, {
            if (BuildConfig.DEBUG) Log.e(TAGS.machine, "machine:out goods>>", it)
        })
}


fun discountUpdate(s: String) {
    Single.just(s).map { json ->
        Gson().fromJson(json, DiscountGson::class.java).apply {
            Log.d(TAGS.machine, this.toString())
            if (avm == machineInfo?.uuid) {
                globalChannelEntityMap.forEach { entry ->
                    if (entry.value.barcode == barcode) {
                        GoodsHelper.getInstance()
                            .add(entry.value.apply { discount = newDiscount.toInt() })
                    }
                }
            }
        }
    }
        .subscribeOn(Schedulers.single())
        .observeOn(Schedulers.single())
        .subscribe({
            Log.d(TAGS.machine, it.toString())
        }, {
            if (BuildConfig.DEBUG) Log.e(TAGS.machine, "machine:discount update>>", it)
        })

}